package com.yequan.leetcode.array.gameOfLife_289;

/**
 * //根据 百度百科 ，生命游戏，简称为生命，是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
 * //
 * // 给定一个包含 m × n 个格子的面板，每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态：1 即为活细胞（live），或 0 即为死细胞（dea
 * //d）。每个细胞与其八个相邻位置（水平，垂直，对角线）的细胞都遵循以下四条生存定律：
 * //
 * //
 * // 如果活细胞周围八个位置的活细胞数少于两个，则该位置活细胞死亡；
 * // 如果活细胞周围八个位置有两个或三个活细胞，则该位置活细胞仍然存活；
 * // 如果活细胞周围八个位置有超过三个活细胞，则该位置活细胞死亡；
 * // 如果死细胞周围正好有三个活细胞，则该位置死细胞复活；
 * //
 * //
 * // 根据当前状态，写一个函数来计算面板上所有细胞的下一个（一次更新后的）状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的，其中细胞的出生
 * //和死亡是同时发生的。
 * //
 * //
 * //
 * // 示例：
 * //
 * // 输入：
 * //[
 * //  [0,1,0],
 * //  [0,0,1],
 * //  [1,1,1],
 * //  [0,0,0]
 * //]
 * //输出：
 * //[
 * //  [0,0,0],
 * //  [1,0,1],
 * //  [0,1,1],
 * //  [0,1,0]
 * //]
 * //
 * //
 * //
 * // 进阶：
 * //
 * //
 * // 你可以使用原地算法解决本题吗？请注意，面板上所有格子需要同时被更新：你不能先更新某些格子，然后使用它们的更新后的值再更新其他格子。
 * // 本题中，我们使用二维数组来表示面板。原则上，面板是无限的，但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题？
 * //
 * // Related Topics 数组
 *
 * @author : Administrator
 * @date : 2020/4/2
 */
public class GameOfLife {

    /**
     * 状态 0： 00，死的，下一轮还是死的
     * 状态 1： 01，活的，下一轮死了
     * 状态 2： 10，死的，下一轮活了
     * 状态 3： 11，活的，下一轮继续活
     * <p>
     * 这个活细胞周围八个位置有两个或三个活细胞，下一轮继续活，属于 11
     * 这个细胞本来死的，周围有三个活着的，下一轮复活了，属于 10
     * <p>
     * 1.遍历数组中所有点,找出周围存活的数量
     * 2.找出上述两种情况,将该位置的分别赋值位 3,2
     * 3.更新结果,将所有位置的 结果往右移动一位,只取高位
     *
     * @param board
     */

    private int[] dx = {-1, 1, 0, 0, -1, -1, 1, 1};
    private int[] dy = {0, 0, -1, 1, -1, 1, -1, 1};
    private int[][] board;
    private int row;
    private int column;

    public void gameOfLife(int[][] board) {

        this.board = board;
        if (board == null || board.length == 0 || board[0] == null || board[0].length == 0) {
            return;
        }

        this.row = board.length;
        this.column = board[0].length;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                int alive = countAlive(i, j);
                if (board[i][j] == 1 && (alive == 2 || alive == 3)) {
                    board[i][j] = 3;
                }
                if (board[i][j] == 0 && alive == 3) {
                    board[i][j] = 2;
                }
            }
        }
        //更新结果
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                board[i][j] >>= 1;
            }
        }

    }

    private int countAlive(int i, int j) {

        int aliveCount = 0;

        for (int k = 0; k < 8; k++) {
            int ni = i + dx[k];
            int nj = j + dy[k];
            if (ni < 0 || ni >= row || nj < 0 || nj >= column) {
                continue;
            }
            // 如果这个位置为 0，代表当前轮是死的，不需要算进去
            // 如果这个位置为 1，代表当前轮是活得，需要算进去
            // 如果这个位置为 2，代表当前轮是死的（状态10，下一轮是活的），不需要算进去
            // 如果这个位置为 3，代表是当前轮是活的（状态11，下一轮也是活的），需要算进去
            aliveCount += (board[ni][nj] & 1);
        }
        return aliveCount;
    }


}
